use crate::json_basic::JsonNode;
use std::ops::{Index, IndexMut};

/// 寻找JSON中 object类型或者array类型 的下一个数据
/// 最主要是用来这样做的 json["courses"], 这个可以用来给 key=courses 的键添加属性的

impl<'a> Index<&'a str> for JsonNode {
    type Output = JsonNode;

    fn index(&self, index: &'a str) -> &Self::Output {
        match self {
            JsonNode::Object(obj) => {
                if obj.contains_key(index) {
                    obj.get(index).unwrap()
                } else {
                    panic!("Key not found")
                }
            }
            _ => panic!("Cannot index non-object type"),
        }
    }
}

impl<'a> IndexMut<&'a str> for JsonNode {
    fn index_mut(&mut self, index: &'a str) -> &mut Self {
        match self {
            JsonNode::Object(obj) => {
                if obj.contains_key(index) {
                    obj.get_mut(index).unwrap()
                } else {
                    obj.insert(index.to_string(), JsonNode::Null);
                    obj.get_mut(index).unwrap()
                }
            }
            _ => panic!("Cannot index non-object type"),
        }
    }
}

impl Index<usize> for JsonNode {
    type Output = JsonNode;

    fn index(&self, index: usize) -> &Self::Output {
        match self {
            JsonNode::Array(arr) => {
                if index < arr.len() {
                    arr.get(index).unwrap()
                } else {
                    panic!("Index out of bounds")
                }
            }
            _ => panic!("Cannot index non-array type"),
        }
    }
}

impl IndexMut<usize> for JsonNode {
    fn index_mut(&mut self, index: usize) -> &mut Self {
        match self {
            JsonNode::Array(arr) => {
                if index < arr.len() {
                    arr.get_mut(index).unwrap()
                } else {
                    panic!("Index out of bounds")
                }
            }
            _ => panic!("Cannot index non-array type"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::json_lexer;
    use crate::json_parser::parse_all;

    #[test]
    fn test_add() {
        let json_str = "{\"first name\":\"Yiran\", \"last name\": \"王\", \"age\":20,\"is_student\":true,\"courses\":[{\"name\":\"CPEN 212\",\"credits\":4},{\"name\":\"CPSC 221\",\"credits\":4},{\"name\":\"Math 256\",\"credits\":3}],\"address\":{\"street\":\"1935 Lower Mall\",\"city\":\"Vancouver\",\"postal_code\":\"V6T 1X1\"},\"friends\":[{\"name\":\"Tommy\",\"age\":20},{\"name\":\"Joe\",\"age\":20}],\"graduated\":false, \"university\": \"UBC\"}";

        // let list = json_lexer::parse_all(json_str).unwrap();
        let mut json = parse_all(json_lexer::parse_all(json_str).unwrap()).unwrap();
        let json2 = parse_all(json_lexer::parse_all("{\"name\":\"ELEC 201\",\"credits\":4}").unwrap()).unwrap();
        let json3 = parse_all(json_lexer::parse_all("{\"name\":\"BIOL 112\",\"credits\":3}").unwrap()).unwrap();
        // println!("json2: {:?}", json2);

        json["courses"].push(json2);
        json["courses"].push(json3);

        json["message"] = JsonNode::Array(vec![
            JsonNode::String("早上好中国！".to_string()),
            JsonNode::String("现在我有冰淇淋，".to_string()),
            JsonNode::String("我很喜欢冰淇淋。".to_string()),
        ]);

        println!("json1: {:?}", json);
        println!("json1: {}", json.dump(2, false));
    }
}
